var gl_alpha1 = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
var gl_alpha2 = "nopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM";
var gl_alnum = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._";
function gl_str_rot13(str) {
	var newStr = "";
	var curLet, curLetLoc;
	for (var i = 0; i < str.length; i++) {
		curLet = str.charAt(i);
		curLetLoc = gl_alpha1.indexOf(curLet);
		newStr += (curLetLoc < 0) ? curLet : gl_alpha2.charAt(curLetLoc);
	}
	return newStr;
}
function gl_base64_encode(str) {
	var out = "";
	var t, x, y, z;
	for (var i = 0; i < str.length; i += 3) {
		t = Math.min(3, str.length - i);
		if (t == 1) {
			x = str.charCodeAt(i);
			out += gl_alnum.charAt((x >> 2));
			out += gl_alnum.charAt(((x & 3) << 4));
			out += "--";
		} else {
			if (t == 2) {
				x = str.charCodeAt(i);
				y = str.charCodeAt(i + 1);
				out += gl_alnum.charAt((x >> 2));
				out += gl_alnum.charAt((((x & 3) << 4) | (y >> 4)));
				out += gl_alnum.charAt(((y & 15) << 2));
				out += "-";
			} else {
				x = str.charCodeAt(i);
				y = str.charCodeAt(i + 1);
				z = str.charCodeAt(i + 2);
				out += gl_alnum.charAt((x >> 2));
				out += gl_alnum.charAt((((x & 3) << 4) | (y >> 4)));
				out += gl_alnum.charAt((((y & 15) << 2) | (z >> 6)));
				out += gl_alnum.charAt((z & 63));
			}
		}
	}
	return out;
}
function gl_ddump(str) {
	dump(str + "\n");
}
function gl_ddumpObject(obj, name, maxDepth, curDepth) {
	if (curDepth == undefined) {
		curDepth = 0;
	}
	if (maxDepth != undefined && curDepth > maxDepth) {
		return;
	}
	var i = 0;
	for (prop in obj) {
		i++;
		if (typeof (obj[prop]) == "object") {
			if (obj[prop] && obj[prop].length != undefined) {
				gl_ddump(name + "." + prop + "=[probably array, length " + obj[prop].length + "]");
			} else {
				gl_ddump(name + "." + prop + "=[" + typeof (obj[prop]) + "]");
			}
			gl_ddumpObject(obj[prop], name + "." + prop, maxDepth, curDepth + 1);
		} else {
			if (typeof (obj[prop]) == "function") {
				gl_ddump(name + "." + prop + "=[function]");
			} else {
				gl_ddump(name + "." + prop + "=" + obj[prop]);
			}
		}
	}
	if (!i) {
		gl_ddump(name + " is empty");
	}
}
function fgladder(e) {
	if (ladder._enable && ladder.is_tbird) {
		if (e.originalTarget instanceof HTMLDocument) {
			var doc = e.originalTarget;
			ladder.adapt(doc);
		}
	}
}
function gl_adapter(str) {
	try{
		this._decode = false;
		if (str.charAt(0) == '#'){
			if (str.charAt(1) == "%"){
				this._type = 0;
				this._decode = true;
				str = str.substr(2);
			}
			else{
				this._type = parseInt(str.substr(1, 2));
				if (isNaN(this._type)){
					this._err = true;
					return;
				}
				str = str.substr(3);
			}
		}
		else{
			this._type = 0;
		}
		var coupe = str.split("\n");
		if (coupe.length < 2) {
			this._err = true;
			return;
		}
		this._src = coupe[0];
		this._dst = coupe[1];
		this._default = false;
		if (this._dst.charAt(0) == ">") {
			this._dst = this._dst.substr(1);
			if (this._dst.charAt(0) == "="){
				this._default = true;
				this._dst = this._dst.substr(1);
			}
		}
		this._err = false;
		this._str = str;
		this._re = new RegExp(this._src, "i");
	}
	catch(e){
		this._err = true;
	}
}
gl_adapter.prototype.toString = function () {
	if (this._decode){
		return "#%" + this._src + "\n" + this._dst;
	}
	else if (this._type == 0){
		return this._src + "\n" + this._dst;
	}
	else{
		return "#"+this._type+this._src + "\n" + this._dst;
	}
};
gl_adapter.prototype.process = function(url ,callback){
	if (this._default){
		callback(this._dst+this.processUrl(url));
		return true;
	}
	if (!this._err && this._re.test(url)) {
		callback(this.processUrl(url));
		return true;
	}
	return false;
};
gl_adapter.prototype.processUrl = function(url){
	switch(this._type){
	case 0:
		if (this._decode){
			var ret = this._dst;
			var res = this._re.exec(url);
//			gl_ddump("url:"+url);
//			gl_ddumpObject(res, "res", 1);
			for (var i=res.length ; i>0; i--){
				var re = new RegExp("\\$"+i, "g");
				ret = ret.replace(re, unescape(res[i]));
			}
//			gl_ddump("ret:"+ret);
			return (ret);
		}
		else{
			return url.replace(this._re, this._dst);
		}
	case 13:
		return this._dst+escape(gl_str_rot13(url));
	case 64:
		return this._dst+gl_base64_encode(url);
	}
}
function gl_progressListener() {
}
gl_progressListener.prototype.QueryInterface = function () {
	return this;
};
gl_progressListener.prototype.onStateChange = function (aWebProgress, aRequest, aStateFlags, aStatus) {
	try {
		if (ladder._enable && !ladder.usingProxy()) {
//			gl_ddumpObject(aWebProgress, "aWebProgress", 0);
//			gl_ddumpObject(aStateFlags, "aStateFlags", 0);
//			gl_ddumpObject(aStatus, "aStatus", 0);
//			gl_ddumpObject(aRequest, "aRequest", 0);
//			gl_ddump("isPending:"+aRequest.isPending());
//			gl_ddumpObject(aRequest.originalURI, "aRequest.originalURI", 0);
			var url = ladder.isErrorPage(aRequest.name)[1];
			ladder.redirect(url);
		}
	}
	catch (e) {
		gl_ddump(e);
	}
};
gl_progressListener.prototype.onProgressChange = function (aWebProgress, aRequest, aCurSelfProgress, aMaxSelfProgress, aCurTotalProgress, aMaxTotalProgress) {
};
gl_progressListener.prototype.onLocationChange = function (aWebProgress, aRequest, aLocation) {
};
gl_progressListener.prototype.onStatusChange = function (aWebProgress, aRequest, aStatus, aMessage) {
};
gl_progressListener.prototype.onSecurityChange = function () {
};
function gladder() {
	this._updateIndex = 0;
	this._adapters = new Array;
	this._namePrefEnable = "gladder.enabled";
	this._namePrefAdapters = "gladder.adapters";
	this._namePrefUpdateURL = "gladder.updateurl";
	this._namePrefUpdateTimeout = "gladder.updatetimeout";
	this._nameStatusImg = "gladderStatusImage";
	this._pref = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService);
	this._enable = true;
	this._defaultAda = null;
	this._timeout = 3600000;
}
gladder.prototype.usingProxy = function(){
	return this._pref.getIntPref("network.proxy.type") > 0;
}
gladder.prototype.adapt = function (doc) {
	var allLinks = doc.links;
	for (var j = 0; j < this._adapters.length; j += 1) {
		var ada = this._adapters[j];
		for (var i = 0; i < allLinks.length; i += 1) {
			ada.process(allLinks[i].href, callback);
		}
	}
	function callback(url){
		allLinks[i].href = url;
		var title = allLinks[i].getAttribute("title");
		if (title) {
			title += " (" + ladder.getString("tooltip.track") + ")";
		} else {
			title = ladder.getString("tooltip.track");
		}
		allLinks[i].setAttribute("title", title);
	}
};
gladder.prototype.redirect = function (url) {
	var _url = url;
	var modified = false;
	for (var j = 0; j < this._adapters.length; j += 1) {
		var ada = this._adapters[j];
		if (ada.process(url, function(rp){url = rp;})){
			modified = true;
		}
	}
	if (modified){
		content.location.replace(url);
	}
	return modified;
};
gladder.prototype.isErrorPage = function(url){
	var errorPage = false;
	if (url.substring(0, 14) == "about:neterror") {
		var re = new RegExp("&u=([^&]*)");
		var arr;
		if ((arr = re.exec(url)) !== undefined) {
			url = arr[1];
		}
		url = unescape(url);
		errorPage = true;
	}
	return [errorPage, url];
}
gladder.prototype.check = function (url) {
//	gl_ddump(url);
	var arr = this.isErrorPage(url);
	var errorPage = arr[0];
	url = arr[1];
	if (!this.redirect(url) && errorPage && this._defaultAda !== null) {
//		gl_ddump("default:"+url);
		this._defaultAda.process(url, function(url){content.location.replace(url);});
	}
};
gladder.prototype.getString = function (name) {
	if (!this._stringBundle) {
		this._stringBundle = document.getElementById("gladderstrings");
	}
	return this._stringBundle.getString(name);
};
gladder.prototype.doLoad = function () {
	ladder._enable = ladder._pref.getBoolPref(ladder._namePrefEnable);
	ladder._timeout = ladder._pref.getIntPref(ladder._namePrefUpdateTimeout);
//	gl_ddump(ladder._timeout);
	ladder.loadAdapters(ladder._pref.getCharPref(ladder._namePrefAdapters));
	if (!ladder._enable) {
		var img = document.getElementById(ladder._nameStatusImg);
		img.src = "chrome://gladder/skin/gladderD.png";
		img.setAttribute("tooltiptext", ladder.getString("status.tooltip.disabled"));
	}
	ladder.update();
	this.is_tbird = (navigator.userAgent.search(/Thunderbird\/\d+/) != -1);
	if (!this.is_tbird){
		gBrowser.addProgressListener(new gl_progressListener, Components.interfaces.nsIWebProgress.NOTIFY_ALL);
	}
//	if (gBrowser.tabContainer){
//		gBrowser.tabContainer.addEventListener("TabOpen", ladder.TabOpen, false);
//	}
//	else if (gBrowser.mPanelContainer){
//		gBrowser.mPanelContainer.addEventListener("DOMNodeInserted", ladder.DOMNodeInserted, false);
//	}
};
//gladder.prototype.TabOpen = function(event) {
//	gl_ddump("tabOpen");
//  var browser = event.target.linkedBrowser;
//  browser.addProgressListener(new gl_progressListener());
//};
//gladder.prototype.DOMNodeInserted = function(event){
//	gl_ddump("DOMNodeInserted");
//  if (event.relatedNode != gBrowser.mPanelContainer)
//    return;
//  var browser;
//  if (event.target.localName == "vbox"){
//    browser = event.target.childNodes[1];
//  browser.addProgressListener(new gl_progressListener());
////		browser.addEventListener("open", function (event) {
////			try{
////				if (ladder._enable){
////					ladder.redirect(event.originalTarget.URL);
////				}
////			}catch(e){}
////		}, false);
//  }
//};
gladder.prototype.update = function () {
	setTimeout(function () {
		ladder.update();
	}, this._timeout);
	var update = this._pref.getCharPref(this._namePrefUpdateURL);
	var list = update.split("\n");
	if (this._updateIndex >= list.length) {
		this._updateIndex = 0;
	}
	try {
		var xmlhttp = new XMLHttpRequest();
//		gl_ddump("gladder update from: "+list[this._updateIndex]);
		xmlhttp.open("GET", list[this._updateIndex], true);
		xmlhttp.onreadystatechange = function () {
			try {
				if (xmlhttp.readyState == 4) {
					if (xmlhttp.status == 200) { //We actually want to catch bad pages
//						gl_ddump(xmlhttp.responseText);
						ladder.processUpdate(xmlhttp.responseText);
					} else {
						ladder._updateIndex += 1;
						ladder.update();
					}
				}
			}
			catch (e) {
				gl_ddump(e);
				ladder._updateIndex += 1;
				ladder.update();
				return;
			}
		};
		xmlhttp.setRequestHeader("Cache-Control", "no-cache");
		xmlhttp.setRequestHeader("If-Modified-Since", "Sat, 29 Oct 1994 19:43:31 GMT");
		xmlhttp.send(null);
	}
	catch (e) {
		gl_ddump(e);
		return;
	}
};
gladder.prototype.processUpdate = function (response) {
	if (response.length > 0) {
		this.loadAdapters(response);
		if (this._defaultAda !== null){
			this._pref.setCharPref(this._namePrefAdapters, this._adapters.join("\n\n") + "\n\n#"+this._defaultAda._type+"\n>="+this._defaultAda._dst);
		}
		else{
			this._pref.setCharPref(this._namePrefAdapters, this._adapters.join("\n\n"));
		}
	}
};
gladder.prototype.loadAdapters = function (str) {
	var adas = str.split("\n\n");
	this._adapters = new Array;
	for (var i = 0; i < adas.length; i += 1) {
		if (adas[i].length > 0) {
			var ada = new gl_adapter(adas[i]);
			if (!ada._err) {
				if (ada._default){
					this._defaultAda = ada;
				}
				else{
					this._adapters.push(ada);
				}
			}
		}
	}
};
gladder.prototype.clickStatus = function (e) {
	if (e.button == 0) {
		if (!this.is_tbird){
			var url = content.document.URL;
			this.check(url);
		}
		this.adapt(window.content.document);
	} else {
		if (e.button == 1) {
			if (!this.is_tbird){
				gBrowser.selectedTab = gBrowser.addTab("http://groups.google.com/group/gladder");
			}
		} else {
			if (e.button == 2) {
				this._enable = !this._enable;
				this._pref.setBoolPref(this._namePrefEnable, this._enable);
				var img = document.getElementById(this._nameStatusImg);
				if (this._enable) {
					img.src = "chrome://gladder/skin/gladder.png";
					img.setAttribute("tooltiptext", this.getString("status.tooltip.enabled"));
				} else {
					img.src = "chrome://gladder/skin/gladderD.png";
					img.setAttribute("tooltiptext", this.getString("status.tooltip.disabled"));
				}
			}
		}
	}
};

